package collect

import (
	"context"
	"strconv"
	"strings"

	"mall/common/ctxdatax"
	"mall/common/enumx"
	"mall/common/moneyx"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/rpc/forumclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type CollectListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCollectListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CollectListLogic {
	return &CollectListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CollectListLogic) CollectList(req *types.CollectListReq) (resp *types.CollectListResp, err error) {
	var page int64 = 1
	var pageSize int64
	if req.Current > 1 {
		page = req.Current
	}
	if req.PageSize > 0 { // 指定，检查最大值
		pageSize = req.PageSize
		if pageSize > l.svcCtx.Config.Query.MaxAmount {
			pageSize = l.svcCtx.Config.Query.MaxAmount
		}
	} else { // 不指定，使用默认值
		pageSize = l.svcCtx.Config.Query.DefaultAmount
	}

	userId := ctxdatax.GetUserId(l.ctx)

	var filters []string
	filters = append(filters, "ObjectType,equalTo:" + strconv.FormatInt(int64(enumx.PostTypeKnowledgeBase), 10))
	var preload string
	var eagerLoad string
	preload = "forumCollect:Id,UserId,ObjectId,ObjectType,Status,UpdatedAt"
	eagerLoad = "forumCollect:total"
	if req.Private { // 我的收藏
		filters = append(filters, "UserId,equalTo:" + strconv.FormatInt(int64(userId), 10))
	} else if req.UserId > 0 {
		filters = append(filters, "UserId,equalTo:" + strconv.FormatInt(req.UserId, 10))
	}
	res, err := l.svcCtx.ForumRpc.CollectList(l.ctx, &forumclient.CollectListReq{
		Offset:     int32((page-1)*pageSize),
		Limit:      int32(pageSize),
		Preload:    preload,
		EagerLoad:  eagerLoad,
		Filter:     strings.Join(filters, ";"),
		Sorter:     req.Sorter,
		VisitorId:  int64(userId),
		PlatformId: int32(enumx.ThirdPartyPlatformWechatMini),
	})
	if err != nil {
		return nil, err
	}

	var list []*types.PerfumeInfo
	if len(res.Data) > 0 {
		var ids []string
		for _, item := range res.Data {
			if enumx.PostType(item.ObjectType) == enumx.PostTypeKnowledgeBase {
				ids = append(ids, strconv.FormatInt(item.ObjectId, 10))
			}
		}

		perfumeMap, perfumeErr := l.getPerfumeMap(ids)
		if perfumeErr != nil {
			return nil, perfumeErr
		}

		if perfumeMap != nil {
			for _, item := range res.Data {
				if parent, exist := perfumeMap[item.ObjectId]; exist {
					list = append(list, parent)
				}
			}
		}
	}

	return &types.CollectListResp{
		Current:         page,
		PageSize:        pageSize,
		List:            list,
		HasNextPage:     res.HasNextPage > 0,
		HasPreviousPage: res.HasPreviousPage > 0,
		Total:           res.Total,
	}, nil
}

func (l *CollectListLogic) getPerfumeMap(ids []string) (map[int64]*types.PerfumeInfo, error) {
	if len(ids) == 0 {
		return nil, nil
	}

	res, err := l.svcCtx.BlogRpc.BookList(l.ctx, &blogclient.BookListReq{
		Preload:   "blogBook:Id,Title,Slug;blogMedia:Id,Uid,Url,Thumbnail,Order;blogBookMeta:year,averageRating;blogBookRelation:brand",
		EagerLoad: "blogBook:blogMedia,blogBookMeta,blogBookRelation",
		EntryIds:  strings.Join(ids, ","),
	})
	if err != nil {
		return nil, err
	}

	if len(res.Data) > 0 {
		resp := make(map[int64]*types.PerfumeInfo)
		for _, item := range res.Data {
			var media []*types.ForumMedia
			if len(item.Media) > 0 {
				for _, m := range item.Media {
					media = append(media, &types.ForumMedia{
						Uid:       m.Uid,
						Id:        m.Id,
						Url:       m.Url,
						Thumbnail: m.Thumbnail > 0,
						Details:   m.Meta,
						Order:     m.Order,
					})
				}
			}
			var brand []*types.PerfumeInfo
			if len(item.Relations) > 0 {
				for _, r := range item.Relations {
					if r.Section == "brand" {
						brand = append(brand, &types.PerfumeInfo{
							Id:    r.Id,
							Title: r.Title,
							Slug:  r.Slug,
						})
					}
				}
			}
			var year string
			var averageRating string
			var minProductGems string
			if len(item.Meta) > 0 {
				for _, m := range item.Meta {
					switch m.Key {
					case "year":
						year = m.Value
					case "averageRating":
						if f, err := strconv.ParseFloat(m.Value, 64); err == nil {
							averageRating = moneyx.FormatStar(f, 1)
						}
					case "minProductGems":
						minProductGems = m.Value
					}
				}
			}

			resp[item.Id] = &types.PerfumeInfo{
				Id:             item.Id,
				Title:          item.Title,
				Slug:           item.Slug,
				Year:           year,
				AverageRating:  averageRating,
				MinProductGems: minProductGems,
				Media:          media,
				Brand:          brand,
			}
		}

		return resp, nil
	}

	return nil, nil
}
